<?php

namespace app\base\model\user;

use think\Model;
use app\core\cache\RedisCache;
use app\core\exception\BusinessException;
use app\core\exception\ErrorCode;
use think\Request;
use app\core\log\Log4dd;
use think\Db;

class UserAccount extends Model
{

    // 关闭自动写入时间戳
    protected $autoWriteTimestamp = false;

    protected $table = 'xy_user.xy_user_account';

    const WISH_COIN = 'wish_coin_num';//心愿值的字段

    const FIRST_SUPPORT_OPERATION_TYPE = 'first_support_wish';

    public function __construct($data = [])
    {
        parent::__construct($data);
        RedisCache::selectDB(config('redis_db_index.account'));
    }

    /**
     * Desc: 根据用户id获取用户的心愿币
     * Date: 2020/1/29 17:11
     * Author: yiyu
     * @param $user_id
     * @return int
     */
    public static function getWishCoinNumByUserId($user_id)
    {
        $num = self::where('user_id', $user_id)->value('wish_coin_num');

        return (float)$num ?? 0;
    }

    /**
     * Desc: 操作用户账户，并记录日志
     * Date: 2020/1/30 13:07
     * Author: yiyu
     * @param int $user_id 用户id
     * @param int $related_id 关联用户id
     * @param string $account_type 操作的币种类型
     * @param float $operation_number 操作的数量
     * @param string $operation_type 操作类型
     * @param int $group_id 拼团id
     * @param string $description 操作详细描述
     * @param bool $force 是否强制扣费
     * @return mixed
     */
    public static function operationUserAccount(
        $user_id,
        $related_id,
        $account_type,
        $operation_number,
        $operation_type,
        $description = '',
        $group_id = 0,
        $force = false
    ) {

        Log4dd::info('操作用户账户 传参', func_get_args());
        Db::startTrans();
        $lockKey = 'operation_user_account:' . $user_id;
        while (RedisCache::setNx($lockKey, 1)) {
            usleep(50000);
        }
        RedisCache::expire($lockKey, 2);


        if (!in_array($account_type, [self::WISH_COIN])) {
            Db::rollback();
            throw new BusinessException(ErrorCode::COMMON_ERROR,'操作未知币种');
        }

        $log_account_type = self::getLogAccountType($account_type);

        if (empty($operation_number)) {
            Db::rollback();
            throw new BusinessException(ErrorCode::COMMON_ERROR,'要操作的币种数量为空');
        }

        if (empty($operation_type)) {
            Db::rollback();
            throw new BusinessException(ErrorCode::COMMON_ERROR,'操作类型不能为空');
        }

        //获取当前的余额详情
        $account_info = self::get($user_id);

        Log4dd::info('操作用户账户 获取用户账号', [func_get_args(), $account_info]);

        if ($operation_number < 0 && true == $force && (empty($account_info) || $account_info[$account_type] < abs($operation_number))) {
            Db::rollback();
            throw new BusinessException(ErrorCode::COMMON_ERROR,'账户余额不够');
        }

        $date = date('Y-m-d H:i:s');


        //新增记录
        if (empty($account_info)) {
            $surplus_num = $operation_number;
            $data = [
                'user_id' => $user_id,
                $account_type => $surplus_num,
                'create_time' => $date,
            ];

            Log4dd::info('操作用户账户 新增数据', $data);

            $model = self::create($data);
            if (!$model->user_id) {
                Db::rollback();
                throw new BusinessException(ErrorCode::DATA_OPERATE_FAIL, '新增用户账户失败');
            }
        } else {//更新记录
            $surplus_num = max(0, $account_info[$account_type] + $operation_number);
            $data = array(
                $account_type => $surplus_num,
                'update_time' => $date,
            );
            Log4dd::info('操作用户账户 更新数据', $data);
            $res = self::where('user_id', $user_id)->update($data);
            if (!$res) {
                Db::rollback();
                throw new BusinessException(ErrorCode::DATA_OPERATE_FAIL, '更新用户账户失败');
            }

        }

        $actually_paid = $operation_number; // 实付
        // 某些原因可能会扣成负数，规避这些风险
        if ($surplus_num < 0) {
            $surplus_num = 0;
            $actually_paid = 0 - $account_info[$account_type];
        }

        //写入日志
        $log = array(
            'user_id' => $user_id,
            'related_id' => $related_id,
            'group_id' => $group_id,
            'operation_type' => $operation_type,
            'account_type' => $log_account_type,
            'operation_number' => $actually_paid, // 操作数量
            'account_count' => $surplus_num, // 余额
            'description' => $description,
            'ip_addr' => Request::instance()->ip(),
            'create_time' => $date,
        );
        $account_log_model = UserAccountLog::create($log);

        if (!$account_log_model->log_id) {
            Db::rollback();
            throw new BusinessException(ErrorCode::DATA_OPERATE_FAIL, '操作账户日志失败');
        }

        //非强制扣费时，需要操作的必须等于实际操作的数目
        if ($force == false && $operation_number != $actually_paid) {
            Db::rollback();
            throw new BusinessException(ErrorCode::COMMON_ERROR,'操作数目有误');
        }

        $result['err_num'] = 0;
        $result['operation_number'] = $operation_number;//需要操作的
        $result['actually_number'] = $actually_paid;//实际操作的
        $result['surplus_num'] = $surplus_num;//剩余
        $result['log_id'] = $account_log_model->log_id;

        RedisCache::del($lockKey);

        Db::commit();

        return $result;

    }

    public static function getLogAccountType($account_type)
    {
        switch ($account_type) {
            case self::WISH_COIN:
                $log_account_type = 1;
                break;
            default:
                $log_account_type = 1;
                break;
        }

        RETURN $log_account_type;
    }

}